// Decompiled by Jad v1.5.7g. Copyright 2000 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi 
// Source File Name:   TupleSpace.java

package lights.dracots;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import lights.interfaces.ITuple;
import lights.interfaces.ITupleSpace;
import lights.interfaces.TupleSpaceError;
import lights.interfaces.TupleSpaceException;

// Referenced classes of package lights:
//            Tuple

public class TupleSpace implements ITupleSpace, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2153303693177117738L;
	public static final int SPEED = 0;
	public static final int SPACE = 1;
	private static HashMap NAME_TS_MAP = new HashMap();
	private String name;
	protected LinkedList<ITuple> ts;
	protected int optimizationFor;

	public TupleSpace() {
		this("_aTupleSpace_", SPACE);
	}

	public TupleSpace(String name) {
		this(name, SPACE);
	}

	public TupleSpace(String name, int optimizeFor) {
		optimizationFor = SPACE;
		if (name == null)
			throw new IllegalArgumentException("Must specify a non-null name.");
		this.name = name;
		ts = new LinkedList();
		if (optimizeFor != SPACE && optimizeFor != SPEED) {
			throw new IllegalArgumentException(
					"Optimization must be for SPACE or SPEED.");
		} else {
			optimizationFor = optimizeFor;
		}
		NAME_TS_MAP.put(name, this);
	}

	public String getName() {
		return name;
	}

	public void out(ITuple tuple) throws TupleSpaceException {
		insertTuple(tuple);
		synchronized (this) {
			notifyAll();
		}
	}

	public void outg(ITuple tuples[]) throws TupleSpaceException {
		synchronized (this) {
			for (int i = 0; i < tuples.length; i++)
				insertTuple(tuples[i]);

			notifyAll();
		}
	}

	public ITuple in(ITuple template) throws TupleSpaceException {
		ITuple result;
		for (result = null; result == null;) {
			result = inp(template);
			if (result == null)
				try {
					synchronized (this) {
						wait();
					}
				} catch (InterruptedException e) {
					throw new TupleSpaceError("Internal Error. Halting...");
				}
		}

		return result;
	}

	public ITuple inp(ITuple template) throws TupleSpaceException {
		ITuple result = null;
		synchronized (this) {
			if (ts.size() != 0)
				result = lookupTuple(template, false);
		}
		return result;
	}

	public ITuple[] ing(ITuple template) throws TupleSpaceException {
		ITuple result[] = (ITuple[]) null;
		synchronized (this) {
			if (ts.size() != 0)
				result = lookupTuples(template, false);
		}
		return result;
	}

	public ITuple rd(ITuple template) throws TupleSpaceException {
		ITuple result;
		for (result = null; result == null;) {
			result = rdp(template);
			if (result == null)
				try {
					synchronized (this) {
						wait();
					}
				} catch (InterruptedException e) {
					throw new TupleSpaceError("Internal Error. Halting...");
				}
		}

		return result;
	}

	public ITuple rdp(ITuple template) throws TupleSpaceException {
		ITuple result = null;
		synchronized (this) {
			if (ts.size() != 0)
				result = lookupTuple(template, true);
		}
		return result;
	}

	public ITuple[] rdg(ITuple template) throws TupleSpaceException {
		ITuple result[] = (ITuple[]) null;
		synchronized (this) {
			if (ts.size() != 0)
				result = lookupTuples(template, true);
		}
		return result;
	}

	public int count(ITuple template) throws TupleSpaceException {
		int c = 0;
		synchronized (this) {
			for(ITuple t: ts) {
				if (template.matches(t))
					c++;
			}
		}
		return c;
	}

	public String toString() {
		return ts.toString();
	}

	protected void insertTuple(ITuple tuple) {
		if (tuple.length() == 0)
			throw new IllegalArgumentException(
					"Tuples with no fields can be used only as templates.");
		byte serTuple[] = ((Tuple) tuple).getSerializedForm();
		ITuple toWrite = Tuple.deserialize(serTuple);
		if (optimizationFor != 1)
			((Tuple) toWrite).setSerializedForm(serTuple);
		ts.add(toWrite);
	}

	protected ITuple lookupTuple(ITuple template, boolean isRead) {
		ITuple result = null;
		ITuple toReturn = null;
		boolean found = false;
		if (template.length() == 0) {	
			if (!isRead)
				toReturn = ts.remove();
			else
				toReturn = ts.getFirst();
		} else {
			Iterator<ITuple> it = ts.iterator();
			for (; !found && it.hasNext(); ) {
				result = it.next();
				found = template.matches(result);
			}

			if (!found) {
				result = null;
			} else {
				if (isRead)
					switch (optimizationFor) {
					case 0: // '\0'
						toReturn = ((Tuple) result).getDeepCopy();
						break;

					case 1: // '\001'
						toReturn = ((Tuple) result).createDeepCopy();
						break;
					}
				else
					toReturn = result;
				if (!isRead)
					it.remove();
			}
		}
		return toReturn;
	}

	protected ITuple[] lookupTuples(ITuple template, boolean isRead) {
		boolean found = false;
		LinkedList allResult;
		ITuple toReturn[] = (ITuple[]) null;
		if (template.length() == 0) {
			allResult = ts;
			found = true;
		} else {
			allResult = new LinkedList();
			Iterator<ITuple> it = ts.iterator();
			for (;it.hasNext();) {
				ITuple t = it.next();
				if (template.matches(t)) {
					if (isRead)
						switch (optimizationFor) {
						case 0: // '\0'
							allResult.add(((Tuple) t).getDeepCopy());
							break;

						case 1: // '\001'
							allResult.add(((Tuple) t).createDeepCopy());
							break;
						}
					else
						allResult.add(t);
					if (!isRead)
						it.remove();
					found = true;
				}
			}

		}
		if (!found) {
			toReturn = (ITuple[]) null;
		} else {
			toReturn = new ITuple[allResult.size()];
			allResult.toArray(toReturn);
		}
		if (template.length() == 0 && !isRead)
			ts.clear();
		return toReturn;
	}
	
	/**
	 * Dump the tuple space into a file and return its size. When you invoke
	 * this method, you should always make sure that the there are no tuple
	 * access anymore. If you used the tuple space in DracoTS, use this method
	 * only when the LimeServer is shut down.
	 * @return the size of dump file, or -1 if the tuple space's name 
	 * with specified name is not found
	 * @param name tuple space name
	 * @author Xing Jiankuan
	 */
	public static long dump(String name) {
		TupleSpace thatTS = (TupleSpace) NAME_TS_MAP.get(name);
		if(thatTS == null)
			return -1L;
		
		ObjectOutputStream out = null;
		String filename = name + ".ts.dump";
		try {
			out = new ObjectOutputStream(new FileOutputStream(filename));
			Iterator it = thatTS.ts.iterator();
			for (;it.hasNext();) {
				Tuple t = (Tuple)it.next();
				out.writeObject(t._fields);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try{
				if (out != null)
					out.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		
		File f = new File(filename);
		return f.length();
	}
}
